AudioClipA single decoded audio clip that can send its signal to a Channel or a Master, be played, looped, analyzed, and controlled over time.
import { AudioClip } from "@fluex/fluexgl-dsp";
const clip = new AudioClip(data);
clip.send(myChannel);
// Basic settings
clip.setVolume(0.8);
clip.setPanLevel(-0.2);
clip.setLoop(true);
// Start playback
clip.play();
// Manually seek to 30 seconds
clip.seek(30);
Constructs a new AudioClip from pre-decoded source data.
new AudioClip(data: AudioSourceData): AudioClip;
data: AudioSourceData - A typed object created when calling loadAudioSource() or loadAudioSourceFromBlob().id: stringA unique id, automatically generated when constructing a new audio clip. Should NOT be changed.
label: string | nullA custom label. Can be changed.
loop: booleanWhether the clip is set to loop when played.
isPlaying: booleanIndicates whether this clip is currently playing.
startTime: numberThe AudioContext.currentTime at which the current playback started.
offsetAtStart: numberThe offset (in seconds) inside the buffer from which playback started.
playbackRate: numberThe current playback rate applied to buffer sources. Defaults to 1. Updated automatically by setPitch().
pitch: numberThe current pitch offset in semitones. Defaults to 0. Updated by setPitch()/resetPitch().
minPitchSemitones: numberThe minimum allowed pitch, in semitones, accepted by setPitch(). Defaults to -24.
maxPitchSemitones: numberThe maximum allowed pitch, in semitones, accepted by setPitch(). Defaults to 24.
progressUpdateSpeed: numberThe interval in milliseconds used to track the audio clip's time progress. Default value is 20.
gainNode: GainNode | nullPer-clip gain node used to control volume.
stereoPannerNode: StereoPannerNode | nullPer-clip stereo panner node used to control pan level.
context: AudioContext | nullAudio context, usually inherited from the DSP's pipeline context.
audioClipPlayer: AudioClipPlayer | nullAudioClipPlayer where this audio clip is attached to.
initialize(audioClipPlayer: AudioClipPlayer): voidInitializes the audio clip using the AudioClipPlayer's audio context. Usually not needed because send(channel: Channel | Master) initializes it automatically.
audioClipPlayer: AudioClipPlayer AudioClipPlayer, which is usually automatically generated when creating a new Channel or a new Master;voidplay(timestamp?: number, offset?: number): AudioClip | nullStarts playback of the clip. The audio clip starts from the beginning if no arguments are provided.
timestamp?: number - Absolute AudioContext.currentTime at which to start. If omitted, playback starts immediately. This argument is optional.offset?: number - Offset in seconds inside the buffer to start from.
If omitted, uses the current offsetAtStart.AudioClip - The same AudioClip. Can be used to stack methods.null - Returns null if this method failed, or if the maximum number of concurrent buffer source nodes (maxAudioBufferSourceNodes) has already been reached.seek(seconds: number): AudioClip | voidSeeks to a given position (in seconds) inside the clip, clamped between 0 and duration. If the clip is currently playing, playback is stopped and restarted from the new position; otherwise offsetAtStart is updated for the next play() call.
seconds: number - The position, in seconds, to seek to.AudioClip - The same AudioClip. Can be used to stack methods.stop(): AudioClip | nullStops playback of this clip and disconnects all active buffer sources.
No arguments
AudioClip - The same AudioClip. Can be used to stack methods.null - Returns null if this method failed.setVolume(volume: number): AudioClipSets the clip volume using its GainNode.
volume: number - The desired gain value (linear)AudioClip - The same AudioClip. Can be used to stack methods.setPanLevel(panLevel: number): AudioClipSets the stereo pan level of the clip. Must be between -1 and 1.
panLevel: number - Pan value between -1 (full left) and 1 (full right).AudioClip - The same AudioClip. Can be used to stack methods.setLoop(loop?: boolean): AudioClipEnables or disables looping of this clip.
loop?: boolean - When omitted, defaults to true.AudioClip - The same AudioClip. Can be used to stack methods.setMaxAudioBufferSourceNodes(value: number): AudioClipSets the maximum number of buffer source nodes (default 1). This can only be changed if the overrideMaxAudioBufferNodes property on DSP is set to true; otherwise a warning is logged and the value is left unchanged.
value: number - The desired maximum amount of buffer source nodes.AudioClip - The same AudioClip. Can be used to stack methods.disconnectAllAudioBufferSourceNodes(): booleanStops and disconnects every currently active buffer source node for this clip.
No arguments
boolean - true if the operation ran, false if this clip has no context.setPitch(semitones: number): AudioClipSets the pitch of the clip in semitones, recalculating and applying the equivalent playbackRate (2 ^ (semitones / 12)) to all active buffer sources.
semitones: number - The desired pitch offset in semitones. Must be between minPitchSemitones and maxPitchSemitones.AudioClip - The same AudioClip. Can be used to stack methods.resetPitch(): AudioClipResets the pitch back to 0 semitones. Shorthand for setPitch(0).
No arguments
AudioClip - The same AudioClip. Can be used to stack methods.setPlaybackRateInSemitones(semitones: number): AudioClipDeprecated. Use
setPitch()instead.
semitones: number - The desired pitch offset in semitones.AudioClip - The same AudioClip. Can be used to stack methods.getChannelData(channel?: number): Float32ArrayReturns the raw PCM sample data for a single channel of the underlying AudioBuffer.
channel?: number - Zero-based channel index. Defaults to 0.Float32ArrayaddEventListener<K extends keyof AudioClipEventMap>(event: K, cb: AudioClipEventMap[K]): () => voidRegisters a listener for clip events.
event: K (keyof AudioClipEventMap) - Event name (e.g. "progress").cb: (event: (event from keyof AudioClipEventMap)) => void - Callback function.() => void - Unsubscribe function to remove the listener.once<K extends keyof AudioClipEventMap>(event: K, cb: AudioClipEventMap[K]): () => voidRegisters a one-time event listener that automatically removes itself after the first call.
event: K (keyof AudioClipEventMap) - Event name (e.g. "progress").cb: (event: (event from keyof AudioClipEventMap)) => void - Callback function.() => void - Unsubscribe function to remove the listener.removeEventListener<K extends keyof AudioClipEventMap>(event: K, cb: AudioClipEventMap[K]): AudioClipRemoves a specific listener from an event.
event: K (keyof AudioClipEventMap) - Event name (e.g. "progress").cb: (event: (event from keyof AudioClipEventMap)) => void - Callback function.AudioClip - The same instance, for chaining.clearEventListeners(event?: keyof AudioClipEventMap): AudioClipClears event listeners.
event?: keyof AudioClipEventMap - If provided, clears listeners only for that event.AudioClip - The same instance, for chainingsend(channel: Channel | Master): voidAttaches this audio clip to a Channel or a Master and sends its signal to the channel.
voidunsend(channel: Channel | Master): voidDetaches this audio clip from a Channel or a Master and stops sending this clip's signal to the channel.
voiddetachFromAudioClipPlayer(audioClipPlayer: AudioClipPlayer): voidDetaches this clip from a specific AudioClipPlayer. If that player was the clip's active player, the next remaining player (if any) becomes active. If no players remain, the clip is stopped.
audioClipPlayer: AudioClipPlayer - The player to detach from.void"progress"Emitted periodically while the clip is playing, on an interval controlled by progressUpdateSpeed.
Payload type (AudioClipOnProgressEvent):
type ProgressPayload = {
current: number; // Current playback position in seconds
startTime: number; // AudioContext timestamp when playback started
offset: number; // Offset in seconds at which playback started
contextTimestamp: number; // Current AudioContext.currentTime
formatted: string; // Human readable time, e.g. "01:23"
};
Registered via
clip.addEventListener("progress", (event) => {
console.log(event.current, event.formatted);
});
"initialize"Emitted once, right after initialize() finishes wiring up this clip's audio nodes.
Payload (simplified):
type InitializePayload = {
durationOfInitialization: number; // Time in ms the initialization took
context: AudioContext | null;
};
"play"Emitted every time play() successfully starts a new buffer source.
Payload (simplified):
type PlayPayload = {
timestamp: number; // Date.now() at play time
audioBufferSourceNodes: AudioBufferSourceNode[]; // All currently active buffer sources
context: AudioContext;
};
get currentPlaybackTime(): numberReturns the current playback time in seconds relative to the start of the buffer. Returns 0 when the clip is not playing or no audio context is available. Otherwise: offsetAtStart + (audioContext.currentTime - startTime).
get duration(): numberTotal duration of the underlying audio buffer in seconds.
get volume(): numberCurrent gain value read from gainNode. Returns 0 when no gain node is available.
get stereoPanning(): numberCurrent pan value read from stereoPannerNode. Returns 1 when no stereo panner node is available.
get formattedDuration(): stringDuration formatted as "mm:ss".
get sampleRate(): numberSample rate of the underlying AudioBuffer.
get numberOfChannels(): numberNumber of channels in the underlying AudioBuffer.
get byteLength(): numberByte length of the original ArrayBuffer used to construct this clip.
import { DspPipeline, loadAudioSource, AudioClip } from "@fluex/fluexgl-dsp";
(async function() {
const pipeline = new DspPipeline({
pathToWasm: "/data/fluexgl-dsp-wasm_bg.wasm",
pathToWorklet: "/data/fluexgl-dsp-processor.worklet"
});
await pipeline.initializeDpsPipeline();
const audioDevice = await pipeline.resolveDefaultAudioOutputDevice();
if(!audioDevice) return;
const audioSource = await loadAudioSource("/music.mp3");
if(!audioSource) return;
const audioClip = new AudioClip(audioSource);
const myChannel = audioDevice.createChannel();
audioClip.send(myChannel);
myChannel.send(audioDevice.getMasterChannel());
window.addEventListener("mousedown", function() {
audioClip.play();
});
})();
import { DspPipeline, loadAudioSource, AudioClip } from "@fluex/fluexgl-dsp";
(async function() {
const pipeline = new DspPipeline({
pathToWasm: "/data/fluexgl-dsp-wasm_bg.wasm",
pathToWorklet: "/data/fluexgl-dsp-processor.worklet",
options: {
overrideMaxAudioBufferNodes: true
}
});
await pipeline.initializeDpsPipeline();
const audioDevice = await pipeline.resolveDefaultAudioOutputDevice();
if(!audioDevice) return;
const audioSource = await loadAudioSource("/single-gun-shot.mp3");
if(!audioSource) return;
const audioClip = new AudioClip(audioSource);
const myChannel = audioDevice.createChannel();
audioClip.setMaxAudioBufferSourceNodes(200);
audioClip.send(myChannel);
myChannel.send(audioDevice.getMasterChannel());
let lastTimestamp = Date.now();
let isShooting = false;
let shootDelayInMs = 100;
function loop() {
const now = Date.now();
if((now - lastTimestamp >= shootDelayInMs) && isShooting) {
audioClip.play();
lastTimestamp = now;
}
return window.requestAnimationFrame(loop);
}
window.addEventListener("mousedown", function() { isShooting = true; });
window.addEventListener("mouseup", function() { isShooting = false; });
loop();
})();